﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PACKETPARSERMAX20.CORE.UPDATEFIELDS;

namespace PACKETPARSERMAX20.CORE
{
    public abstract class WoWObjectBase
    {
        public ulong Guid { get; private set; }
        public TypeID TypeID { get; private set; }
        internal string _name = null;
        public virtual string Name { get; internal set; }
        public string SubName { get; private set; }
        public UInt32 SubType { get; private set; }

        public IDictionary<int, uint> Fields { get; private set; }
        public WoWCore Sender { get; private set; }


        public WoWObjectBase(WoWCore sender)
        {
            Sender = sender;
            Fields = new Dictionary<int, uint>();
        }

        public WoWObjectBase(WoWCore sender, ulong guid, TypeID typeid)
        {
            Sender = sender;
            Guid = guid;
            TypeID = typeid;
            Fields = new Dictionary<int, uint>();

        }

        private uint? _entry = null;
        public uint ENTRY
        {
            get
            {

                if (_entry == null)
                {
                    _entry = (uint?)GetUpdateValueNullable("OBJECT_FIELD_ENTRY", typeof(uint));

                    if (_entry == null)
                    {
                        return 0;
                    }

                }

                return _entry.Value;
            }
        }

        public ulong OBJECT_FIELD_GUID
        {
            get
            {
                return (ulong)GetUpdateValue("OBJECT_FIELD_GUID", typeof(ulong));
            }
        }

        public int OBJECT_FIELD_TYPE
        {
            get
            {
                return (int)GetUpdateValue("OBJECT_FIELD_TYPE", typeof(int));
            }
        }

        public float OBJECT_FIELD_SCALE_X
        {
            get
            {
                return (float)GetUpdateValue("OBJECT_FIELD_SCALE_X", typeof(float));
            }
        }

        public uint? GetUInt32ValueNullable(int index)
        {
            uint result;
            if (Fields.TryGetValue(index, out result))
            {
                return result;
            }
            else
            {
                return null;
            }

        }

        private uint GetUInt32Value(int index)
        {
            uint result;
            Fields.TryGetValue(index, out result);
            return result;
        }

        public object GetUpdateValue(string pFieldName, Type pType)
        {
            int? tFieldNum = GetEnumByName(pFieldName);
            if (tFieldNum == null) return null;

            if (pType == typeof(ulong))
            {
                uint first = GetUInt32Value(tFieldNum.Value);
                uint second = GetUInt32Value(tFieldNum.Value + 1);

                byte[] b1 = BitConverter.GetBytes(first);
                byte[] b2 = BitConverter.GetBytes(second);

                byte[] tbytes = new byte[8];
                if (first == 0)
                {
                    tbytes[0] = b2[0];
                    tbytes[1] = b2[1];
                    tbytes[2] = b2[2];
                    tbytes[3] = b2[3];
                }
                else
                {
                    tbytes[0] = b1[0];
                    tbytes[1] = b1[1];
                    tbytes[2] = b1[2];
                    tbytes[3] = b1[3];
                    tbytes[4] = b2[0];
                    tbytes[5] = b2[1];
                    tbytes[6] = b2[2];
                    tbytes[7] = b2[3];
                }

                ulong tTest = BitConverter.ToUInt64(tbytes, 0);

                return tTest;// ((UInt64)Fields[tFieldNum] << 32) + (UInt64)Fields[tFieldNum + 1];
            }
            else if (pType == typeof(float))
            {
                byte[] b = BitConverter.GetBytes(GetUInt32Value(tFieldNum.Value));
                float tTest = BitConverter.ToSingle(b, 0);
                return tTest;// (float)Fields[tFieldNum];
            }
            else if (pType == typeof(int))
            {
                return (int)GetUInt32Value(tFieldNum.Value);// (int)Fields[tFieldNum];
            }
            else if (pType == typeof(uint))
            {
                return GetUInt32Value(tFieldNum.Value);
            }
            else if (pType == typeof(byte[]))
            {
                byte[] b = BitConverter.GetBytes(GetUInt32Value(tFieldNum.Value));
                return b;
            }

            return Fields[tFieldNum.Value];
        }


        public object GetUpdateValueNullable(string pFieldName, Type pType)
        {
            var num = GetEnumByName(pFieldName);

            if (num == null) return null;

            if (pType == typeof(ulong))
            {
                uint? first = GetUInt32ValueNullable(num.Value);
                uint? second = GetUInt32ValueNullable(num.Value + 1);

                if (first == null && second == null)
                {
                    return null;
                }
                else
                {
                    byte[] b1 = BitConverter.GetBytes(first.GetValueOrDefault(0));
                    byte[] b2 = BitConverter.GetBytes(second.GetValueOrDefault(0));
                    byte[] tbytes = new byte[8];
                    if (first == 0)
                    {
                        tbytes[0] = b2[0];
                        tbytes[1] = b2[1];
                        tbytes[2] = b2[2];
                        tbytes[3] = b2[3];
                    }
                    else
                    {
                        tbytes[0] = b1[0];
                        tbytes[1] = b1[1];
                        tbytes[2] = b1[2];
                        tbytes[3] = b1[3];
                        tbytes[4] = b2[0];
                        tbytes[5] = b2[1];
                        tbytes[6] = b2[2];
                        tbytes[7] = b2[3];
                    }

                    var res = BitConverter.ToUInt64(tbytes, 0);

                    return res;
                }
            }
            else if (pType == typeof(float))
            {
                var val = GetUInt32ValueNullable(num.Value);
                if (val == null)
                {
                    return val;
                }
                else
                {
                    byte[] b = BitConverter.GetBytes(val.Value);
                    float res = BitConverter.ToSingle(b, 0);
                    return res;
                }
            }
            else if (pType == typeof(int))
            {
                return (int?)GetUInt32ValueNullable(num.Value);
            }
            else if (pType == typeof(uint))
            {
                return GetUInt32ValueNullable(num.Value);
            }
            else if (pType == typeof(byte[]))
            {
                var val = GetUInt32ValueNullable(num.Value);
                if (val == null)
                {
                    return null;
                }
                else
                {
                    byte[] b = BitConverter.GetBytes(val.Value);
                    return b;
                }
            }

            return null;
        }


        public int? GetEnumByName(string pFieldName)
        {
            var t = Type.GetType(string.Format("PACKETPARSERMAX20.CORE.UPDATEFIELDS.UpdateFields_{0}", ((ClientBuild)Sender.ClientBuild).ToString().Replace("v", "")));
            if (t == null || !Enum.IsDefined(t, pFieldName)) return null;
            
            return (int)Enum.Parse(t, pFieldName);
        }


        public MovementInfo movementInfo = new MovementInfo();

        public virtual void UpdateObjectPosition(float x, float y, float z, float o, uint time)
        {
            X = x;
            Y = y;
            Z = z;
            O = o;

            //if (guid == sender.PlayerGUID)
            //{
            //    bool test = true;
            //}
            //movementList.Add(time, new Coord4(X, Y, Z, O));
        }

        public virtual float X
        {
            get
            {
                return movementInfo.positionInfo.X;
            }
            set
            {
                movementInfo.positionInfo.X = value;
            }
        }

        public virtual float Y
        {
            get
            {
                return movementInfo.positionInfo.Y;
            }
            set
            {
                movementInfo.positionInfo.Y = value;
            }
        }

        public virtual float Z
        {
            get
            {
                return movementInfo.positionInfo.Z;
            }
            set
            {
                movementInfo.positionInfo.Z = value;
            }
        }

        public virtual float O
        {
            get
            {
                return movementInfo.positionInfo.O;
            }
            set
            {
                movementInfo.positionInfo.O = value;
            }
        }

        public bool HasPosition()
        {
            return !(X == 0f && Y == 0f && Z == 0f && O == 0f);
        }



        public virtual void UpdateData(OBJECT_UPDATE_TYPE updatetype)
        {

        }

        public virtual void UpdateAuraInfo(DefinitionBase def)
        {

        }


    }
}
